#pragma once
#include "datamanage.hpp"
#include "httplib.h"

extern Cloud::DataManager *_data;
namespace Cloud
{
    class Service
    {
    private:
        int _server_port;
        std::string _server_ip;
        std::string _download_prefix;
        httplib::Server _server;

    private:
        static void Upload(const httplib::Request &req, httplib::Response &rsp)
        {
            // 判断有没有上传的文件区域
            bool ret = req.has_file("file");
            if (ret == false)
            {
                rsp.status == 400;
                return;
            }
            const httplib::MultipartFormData &file = req.get_file_value("file");
            std::string backup_dir = Cloud::Config::GetInstance()->GetBackupDir();
            std::string realpath = backup_dir + Cloud::FileUtil(file.filename).FileName();
            Cloud::FileUtil fu(realpath);
            fu.SetContent(file.content);
            Cloud::BackupInfo info;
            // 设置备份信息
            info.SetBackupInfo(realpath);
            // 向数据管理模块添加数据
            _data->Insert(info);
            return;
        }
        static std::string TimeToString(time_t t)
        {
            std::string tmp = std::ctime(&t);
            return tmp;
        }
        static void ListShow(const httplib::Request &req, httplib::Response &rsp)
        {
            // 获取所有文件备份信息
            std::vector<Cloud::BackupInfo> arr;
            _data->GetAll(&arr);
            // 根据所有文件的备份信息，组织html文件数据
            std::stringstream ss;
            ss << "<html><head><title>Download</title></head>";
            ss << "<body><h1>Download</h1><table>";
            for (auto &a : arr)
            {
                ss << "<tr>";
                ss << "<td><a href='" << a.url << "'>" << Cloud::FileUtil(a.real_path).FileName() << "</a></td>";
                ss << "<td align='right'>" << TimeToString(a.mtime) << "</td>";
                ss << "<td align='right'>" << a.fsize / 1024 << "KB</td>";
                ss << "</tr>";
            }
            ss << "</table></body></html>";
            rsp.body = ss.str();
            rsp.set_header("Content-Type", "text/html");
            rsp.status = 200;
            return;
        }
        static std::string GetTag(const Cloud::BackupInfo &info)
        {
            // ETag filename-fsize-mtime
            Cloud::FileUtil fu(info.real_path);
            std::string etag = fu.FileName();
            etag += '-';
            etag += std::to_string(info.fsize);
            etag += '-';
            etag += std::to_string(info.mtime);
            return etag;
        }
        static void Download(const httplib::Request &req, httplib::Response &rsp)
        {
            // 根据资源路径获取文件备份信息
            Cloud::BackupInfo info;
            _data->GetOneByURL(req.path, &info);
            // 判断文件有没有被压缩，压缩的话就解压，然后删除压缩包，修改备份信息
            if (info.pack_flag == true)
            {
                Cloud::FileUtil fu(info.pack_path);
                // 将文件解压缩到备份文件夹
                fu.UnCompress(info.real_path);
                fu.Remove();
                info.pack_flag = false;
                _data->Updata(info);
            }
            // 判断是否需要断点续传
            bool resume = false;
            std::string old_etag;
            if (req.has_header("If-Range"))
            {
                old_etag = req.get_header_value("If-Range");
                if (old_etag == GetTag(info))
                {
                    // 又If-Range字段并且这个字段与请求文件的最新etag一致则需要断点续传
                    resume = true;
                }
            }
            // 读取文件数据，放入rsp.body中
            Cloud::FileUtil fu(info.real_path);
            fu.GetContent(&rsp.body);
            rsp.set_header("Accept-Ranges", "bytes");
            rsp.set_header("ETag", GetTag(info));
            rsp.set_header("Content-Type", "application/octet-stream");
            if (resume == false)
            {
                rsp.status = 200;
            }
            else
            {
                // httplib内部实现了对断点续传请求的处理，数据读取到rsp.body中，它内部会自动根据请求区间，从body中取出指定区域的数据进行响应
                rsp.status = 206;
            }
        }

    public:
        Service()
        {
            Cloud::Config *config = Cloud::Config::GetInstance();
            _server_port = config->GetServerPort();
            _server_ip = config->GetServerIp();
            _download_prefix = config->GetDownloadPrefix();
        }
        bool RunModule()
        {
            _server.Post("/upload", Upload);
            _server.Get("/listshow", ListShow);
            _server.Get("/", ListShow);
            //.*正则表达式，匹配除\r \n以外的任意字符任意次
            std::string download_url = _download_prefix + "(.*)";
            _server.Get(download_url, Download);
            _server.listen(_server_ip.c_str(), _server_port);
            return true;
        }
    };
}
